﻿using System.Collections.Immutable;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Text.Json;
using rpc_service.cache;

namespace rpc_service.core.support.assembly.il.http.post;

public abstract class ILPostHttpRequest : ILBaseStep
{
    protected void createDataJson(ILGenerator il, LocalBuilder paramLocal, MethodInfo targetMethod)
    {
        Type paramType = targetMethod.GetParameters()[0].ParameterType;

        // 加载参数对象（第一个参数）
        il.Emit(OpCodes.Ldarg_1);

        // 创建 JsonSerializerOptions 并设置属性
        il.Emit(OpCodes.Newobj, "JsonSerializerOptions".GetTypeByStr().GetConstructor(Type.EmptyTypes)!);
        il.Emit(OpCodes.Dup);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Callvirt, "JsonSerializerOptions".GetTypeByStr().GetProperty("PropertyNameCaseInsensitive")!.SetMethod!);

        // 正确获取泛型方法定义
        MethodInfo serializeMethodDefinition = "JsonSerializer".GetTypeByStr().GetMethods()
            .FirstOrDefault(m => m.Name == "Serialize" &&
                                 m.IsGenericMethod &&
                                 m.GetParameters().Length == 2 &&
                                 m.GetParameters()[1].ParameterType == "JsonSerializerOptions".GetTypeByStr())!;

        // 使用参数类型创建特定的泛型方法
        MethodInfo serializeMethod = serializeMethodDefinition.MakeGenericMethod(paramType);

        // 调用序列化方法
        il.Emit(OpCodes.Call, serializeMethod);
        il.Emit(OpCodes.Stloc, paramLocal);
    }

    protected void writeJsonToRequest(ILGenerator il, LocalBuilder requestLocal, LocalBuilder paramLocal)
    {
        LocalBuilder byteLocal = il.DeclareLocal("byte []".GetTypeByStr());
        
        il.Emit(OpCodes.Ldloc, requestLocal);
        il.Emit(OpCodes.Ldstr, "application/json");
        il.Emit(OpCodes.Callvirt, "HttpWebRequest".GetTypeByStr().GetMethod("set_ContentType")!);

        il.Emit(OpCodes.Call, "Encoding".GetTypeByStr().GetMethod("get_UTF8")!);
        il.Emit(OpCodes.Ldloc, paramLocal);
        il.Emit(OpCodes.Callvirt, "Encoding".GetTypeByStr().GetMethod("GetBytes", new []{ typeof(string) })!);
        il.Emit(OpCodes.Stloc, byteLocal);
        
        il.Emit(OpCodes.Ldloc, requestLocal);
        il.Emit(OpCodes.Ldloc, byteLocal);
        il.Emit(OpCodes.Ldlen);
        il.Emit(OpCodes.Conv_I4);
        il.Emit(OpCodes.Conv_I8);
        il.Emit(OpCodes.Callvirt, typeof(HttpWebRequest)!.GetMethod("set_ContentLength", new []{ typeof(Int64) })!);
        
        LocalBuilder requestStreamLocal = il.DeclareLocal(typeof(Stream));
        il.Emit(OpCodes.Ldloc, byteLocal);
        il.Emit(OpCodes.Callvirt, typeof(WebRequest)!.GetMethod("GetRequestStream")!);
        il.Emit(OpCodes.Stloc, requestStreamLocal);
        il.Emit(OpCodes.Ldloc, requestStreamLocal);
        il.Emit(OpCodes.Ldloc, byteLocal);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Ldloc, byteLocal);
        il.Emit(OpCodes.Ldlen);
        il.Emit(OpCodes.Callvirt, typeof(Stream).GetMethod("Write", new[] { typeof(byte[]), typeof(Int32), typeof(Int32) })!);
        il.Emit(OpCodes.Ldloc, requestStreamLocal);
        il.Emit(OpCodes.Callvirt, typeof(Stream).GetMethod("Close")!);
    }
}